
package picsim;

/**
 *
 * @author Daniel
 * @brief Speicherverwaltung des PIC.
 *
 */
public class MemMan {

    private Stack stack;
    private Calculator calc;

    private int instCounter;
    private int realTimeDuration; // one instruction takes 1 µs
    private int timer0Inc_waitCycles; // if timer0 is in timer mode and written wait 2 cycles

    private String lastOpcode;

    GUI gui;


    private boolean bank1; // true, if bank1 is active, else it is false (so bank0 is active)

    // 01h TMR0
    private int tmr0;
    // 02h PCL and W-Register
    private int pcl;
    // 03h STATUS
    private int statusReg[] = new int[8]; // irp | rp1 | rp0 | ^to | ^pd | z | dc | c
    // 04h FSR
    private int fsr;
    // 05h PORTA
    private int portA[] = new int[5]; // RA4/T0CKI | RA3 | RA2 | RA1 | RA0
    private int portA_prev[] = new int[5];
    // 06h PORTB            
    private int portB[] = new int[8]; // RB7 | RB6 | RB5 | RB4 | RB3 | RB2 | RB1 | RB0/INT
    private int portB_prev[] = new int[8];
    // 08h EEDATA
    private int eedata;
    // 09h EEADR
    private int eeadr;
    // 0Ah PCLATH
    private int pclath[] = new int[5];
    // 0Bh INTCON
    private int intcon[] = new int[8]; // GIE | EEIE | T0IE | INTE | RBIE | T0IF | INTF | RBIF
    // 81h OPTION_REG
    private int optionReg[] = new int[8]; // RBPU | INTEDG | T0CS | T0SE | PSA | PS2 | PS1 | PS0
    // 85h TRISA
    private int trisA[] = new int[5]; // TRISA4 | TRISA3 | TRISA2 | TRISA1 | TRISA0
    // 86h TRISB
    private int trisB[] = new int[8]; // TRISB7 | TRISB6 | TRISB5 | TRISB4 | TRISB3 | TRISB2 | TRISB1 | TRISB0
    //88h EECON1
    private int eecon1[] = new int[5]; // EEIF | WRERR | WREN | WR | RD


    // SRAM (GPR)
    private int sram[] = new int[68];
    private final int min0_sram = 0x0C; // bank 0 (sram) -> 0Ch ...
    private final int max0_sram = 0x4F; // bank 0 (sram) -> ... bis 4Fh

    private final int min1_sram = 0x8C; // bank 1 (sram) -> 8Ch ...
    private final int max1_sram = 0xCF; // bank 1 (sram) -> ... bis CFh

    private int w, wdt;

    /**
     * @brief Konstruktor der Klasse MemMan. Initialisierung aller Werte
     */
    public MemMan(GUI pGUI) {

        this.gui = pGUI; // to show error messages
        
        setMemoryToValueOnPowerOn();

        // create new Stack
        stack = new Stack();
        calc = new Calculator();

        instCounter = 0;
        timer0Inc_waitCycles = 0;

    }

    /**
     *
     * @return InstCounter (int)
     * @brief Holt den aktuellen Stand des Instruction Counters
     */
    public int getInstCounter() {
        return instCounter;
    }

     /**
     *
     * @brief Inkrmentiert den Instruction Counter
     */
    public void incInstCounter() {
        instCounter++;
    }

     /**
     *
     * @return realTimeDuration (int)
     * @brief Holt den aktuellen Stand des Real Time Duration Coounters
     */
    public int getRealTimeDuration() {
        return realTimeDuration;
    }

    /**
     *
     * @brief Inkrmentiert den Real Time Duration Counter
     */
    public void incRealTimeDuration() {
        realTimeDuration++;
        wdt++;

        timer0Module();
    }

    /**
     * @brief Implementiert die Timer0-Modul Funktion
     */
    private void timer0Module() {

        // timer mode
        if(getOptionRegValue(5) == 0) { // T0CS

            if(timer0Inc_waitCycles == 0) {

                tmr0++;

                if(tmr0 > 255) { // overflow (FFh -> 00h)
                    tmr0 = tmr0-255;
                    setINTCONRegValue(2, 1); // T0IF is set
                }
                
            }
            else {
                timer0Inc_waitCycles--;
            }

        }


        // counter mode
        if(getOptionRegValue(5) == 1) { // T0CS

            if(getOptionRegValue(4) == 0) { // rising edge?
                if(getPORTAprevRegValue(4) == 0 && getPORTARegValue(4) == 1) { // it's a rising edge!
                    
                    tmr0++;

                    if(tmr0 > 255) {
                        tmr0 = tmr0-255;
                        setINTCONRegValue(2, 1); // T0IF is set
                    }
                    
                }
            }
            else { // falling edge?
                if(getPORTAprevRegValue(4) == 1 && getPORTARegValue(4) == 0) { // it's a falling edge!

                    tmr0++;

                    if(tmr0 > 255) {
                        tmr0 = tmr0-255;
                        setINTCONRegValue(2, 1); // T0IF is set
                    }
                    
                }
            }

        }

    }


    /**
     *
     * @return SFR Value (int)
     * @brief Entscheidet anhand des Prameter regAddr, welches SFR zurückgegeben wird
     */
    public int getSFRValue(int regAddr) {

        int value = 0;

        if(regAddr == 0) { // INDF (indirect)
            return getFSRReg();
        }

        if(regAddr == 1 && bank1) { // OPTION_REG
            return getOptionRegValueSum();
        }
        else if(regAddr == 1) { // TMR0
            return getTMR0Reg();
        }



        else if(regAddr == 2) { // PCL
            getPCL();
        }


        else if(regAddr == 3) { // STATUS
            return getStatusRegValueSum();
        }


        else if(regAddr == 4) { // FSR
             return getFSRReg();
        }



        else if(regAddr == 5 && bank1) { // TRISA
            return getTrisARegValueSum();
        }
        else if(regAddr == 5) { // PORTA
            return getPORTARegValueSum();
        }



        else if(regAddr == 6 && bank1) { // TRISB
            return getTrisBRegValueSum();
        }
        else if(regAddr == 6) { // PORTB
            return getPORTBRegValueSum();
        }

        // regAddr == 7 -> unimplemented

        else if(regAddr == 8 && bank1) { // EECON1
            return getEECON1RegValueSum();
        }
        else if(regAddr == 8) { // EEDATA
            return getEEDATAReg();
        }


        else if(regAddr == 9) { // EEADR
            return getEEADRReg();
        }


        else if(regAddr == 0xA) { // PCLATH
            return getPCLATHRegValueSum();
        }


        else if(regAddr == 0xB) { // INTCON
            return getINTCONRegValueSum();
        }
        
        return value;

    }


    /**
     *
     * @param regAddr (int)
     * @param value (int)
     * @brief Entscheidet anhand des Parameters <code>regAddr</code> welches SFR angesprochen wird und speichert den Parameter <code>value</code> ab
     */
    public void setSFRValue(int regAddr, int value) {
        
        if(regAddr == 0) { // INDF (indirect)
            int indirectAddr = getFSRReg();
            int index = getSramIndex(indirectAddr);
            setSramValue(index, value);
            return; // quitting method
        }

        if(regAddr == 1 && bank1) { // OPTION_REG
            int values[] = calc.getSingleBitValues(optionReg.length, value);
            for(int i=0; i<optionReg.length; i++) {
                setOptionRegValue(i, values[i]);
            }
            return; // quitting method
        }
        else if(regAddr == 1) { // TMR0
            setTMR0(value);

            if(getOptionRegValue(5) == 0) { // timer0 = timer mode
                timer0Inc_waitCycles = 2;
            }

            return; // quitting method
        }



        else if(regAddr == 2) { // PCL
            setPCL(value);
            return; // quitting method
        }


        else if(regAddr == 3) { // STATUS
            int values[] = calc.getSingleBitValues(statusReg.length, value);
            for(int i=0; i<statusReg.length; i++) {
                setStatusRegValue(i, values[i]);
            }
            return; // quitting method
        }


        else if(regAddr == 4) { // FSR
            setFSR(value);
            return; // quitting method
        }



        else if(regAddr == 5 && bank1) { // TRISA
            int values[] = calc.getSingleBitValues(trisA.length, value);
            for(int i=0; i<trisA.length; i++) {
                setTrisARegValue(i, values[i]);
            }
            return; // quitting method
        }
        else if(regAddr == 5) { // PORTA
            int values[] = calc.getSingleBitValues(portA.length, value);
            for(int i=0; i<portA.length; i++) {
                setPortARegValue(i, values[i]);
            }
            return; // quitting method
        }



        else if(regAddr == 6 && bank1) { // TRISB
            int values[] = calc.getSingleBitValues(trisB.length, value);
            for(int i=0; i<trisB.length; i++) {
                setTrisBRegValue(i, values[i]);
            }
            return; // quitting method
        }
        else if(regAddr == 6) { // PORTB
            int values[] = calc.getSingleBitValues(portB.length, value);
            for(int i=0; i<portB.length; i++) {
                setPortBRegValue(i, values[i]);
            }
            return; // quitting method
        }


        // regAddr == 7 -> unimplemented

        else if(regAddr == 8 && bank1) { // EECON1
            int values[] = calc.getSingleBitValues(eecon1.length, value);
            for(int i=0; i<eecon1.length; i++) {
                setEECON1RegValue(i, values[i]);
            }
            return; // quitting method
        }
        else if(regAddr == 8) { // EEDATA
            setEEDATA(value);
            return; // quitting method
        }


        else if(regAddr == 9) { // EEADR
            setEEADR(value);
            return; // quitting method
        }


        else if(regAddr == 0xA) { // PCLATH
            int values[] = calc.getSingleBitValues(pclath.length, value);
            for(int i=0; i<pclath.length; i++) {
                setPCLATHRegValue(i, values[i]);
            }
            return; // quitting method
        }


        else if(regAddr == 0xB) { // INTCON
            int values[] = calc.getSingleBitValues(intcon.length, value);
            for(int i=0; i<intcon.length; i++) {
                setINTCONRegValue(i, values[i]);
            }
            return; // quitting method
        }

        else {
            System.err.println("MemMan: Method [setSFRValue] no return was executed");
        }
        
    }
    // *********


    // SRAM
    // bank 1 = bank 0 (mapped)
    /**
     *
     * @param address (int)
     * @return index (int)
     * @brief Berechnet anhand der übergebenen <code>address</code> den Index des SRAM-Arrays und gibt diesen dann zurück.
     */
    public int getSramIndex(int address) {
        
        int result = -1;

        if(address >= min0_sram && address <= max0_sram) { // bank0 area
            result = max0_sram - address;
        }
        else if(address >= min1_sram && address <= max1_sram) { // bank1 area
            result = max1_sram - address;
        }

        int index = (sram.length - 1) - result;

        if(result == -1) return -1;

        return index;

    }    
    

    /**
     *
     * @param index (int)
     * @return value (int)
     * @brief Gibt den Wert des SRAMs zurück, der unter <code>index</code> abgespeichert ist.
     */
    public int getSramValue(int index) {

        return sram[index];

    }

    /**
     * 
     * @param index (int)
     * @param value (int
     * @brief Speichert im Array (an der Stelle des <code>index</code>) den übergebenen Wert ab
     */
    public void setSramValue(int index, int value) {

        // only 8 bit values can be saved!!
        if(value > 255) {

            String binValue = Integer.toBinaryString(value);
            binValue = binValue.substring(binValue.length()-8); // get the last 8 bit of the string

            sram[index] = Integer.parseInt(binValue, 2);

        }
        else {
            sram[index] = value;
        }
        

    }
    // *********


    // TMR0 Register
    // 01h 8-bit Real-Time Clock/Counter

    /**
     *
     * @return tmr0 (int)
     * @brief Holt ddas TMR0 Register
     */
    public int getTMR0Reg() {
        return tmr0;
    }

    /**
     *
     * @param value (int)
     * @brief Speichert den Parameter <code>value</code> in TMR0
     */
    public void setTMR0(int value) {
        tmr0 = value;
    }
    // *********


    // STATUS Register
    // 03h STATUS IRP, RP1, RP0, TO, PD, Z, DC, C
    /**
     * 
     * @param bit (int)
     * @return value (int)
     * @brief Gibt den Wert des STATUS Registers an der Stelle mit <code>bit</code> spezifizierten Stelle zurück
     */
    public int getStatusRegValue(int bit) {

        return statusReg[bit];
        
    }

    /**
     * 
     * @return sum (int)
     * @brief Berechnet den Gesamtwert des STATUS Registers und gibt diesen zurück
     */
    public int getStatusRegValueSum() {

        String sum = "";
        
        for(int i=0; i<statusReg.length; i++) {
            sum = Integer.toString(statusReg[i]) + sum;
        }
        
        return Integer.parseInt(sum,2);

    }
    
    /**
     * 
     * @param bit (int)
     * @param value (int)
     * @brief Setzt den Wert an Stelle <code>bit</code> des STATUS Registers
     */
    public void setStatusRegValue(int bit, int value) {

        statusReg[bit] = value;

        // toggle Bank
        if(bit == 5 && value == 1) {
            bank1 = true; // we are on bank1
        }
        else if(bit == 5 && value == 0) {
            bank1 = false; // we are on bank0
        }
        // *********

    }
    // *********

    // FSR Register
    // 04h

    /**
     *
     * @return fsr (int)
     * @brief Holt den Wert aus dem FSR Register
     */
    public int getFSRReg() {
        return fsr;
    }

     /**
     *
     * @param value
     * @brief Speichert Wert aus dem Parameter <code>value</code> im FSR
     */
    public void setFSR(int value) {
        fsr = value;
    }
    // *********

    // PORTA
    // 05h PORTA - | - | - | RA4/T0CKI | RA3 | RA2 | RA1 | RA0

    /**
     *
     * @return sum (int)
     * @brief Holt den aktuellen Wert der auf Port A liegt
     */
    public int getPORTARegValueSum() {
        String sum = "";

        for(int i=0; i<portA.length; i++) {
            sum = Integer.toString(portA[i]) + sum;
        }

        return Integer.parseInt(sum,2);
    }

    /**
     *
     * @param bit (int)
     * @param value (int)
     * @brief Setzt den Wert <code>value</code> an Stelle <code>bit</code>
     */
    public void setPortARegValue(int bit, int value) {

        // save previous value
        setPortAprevRegValue(bit, getPORTARegValue(bit));

        // save new value
        portA[bit] = value;
        
    }


    /**
     *
     * @param bit
     * @return bit (int[])
     * @brief Holt den Wert und gibt es als Array zurück
     */
    public int getPORTARegValue(int bit) {
        return portA[bit];
    }

    /**
     * 
     * @param bit (int)
     * @return bit (int)
     * @brief Gibt den letzten Wert des PortA an Stelle <code>bit</code> zurück
     */
    public int getPORTAprevRegValue(int bit) {
        return portA_prev[bit];
    }

    /**
     *
     * @param bit (int)
     * @param value (int)
     * @brief Speichert den letzten Wert von PortA ab
     */
    public void setPortAprevRegValue(int bit, int value) {
        portA_prev[bit] = value;
    }
    // *********

    // PORTB
    // 06h PORTB RB7 | RB6 | RB5 | RB4 | RB3 | RB2 | RB1 | RB0/INT

    /**
     *
     * @return sum (int)
     * @brief Holt den aktuellen Wert der auf Port B liegt
     */
    public int getPORTBRegValueSum() {
        String sum = "";

        for(int i=0; i<portB.length; i++) {
            sum = Integer.toString(portB[i]) + sum;
        }

        return Integer.parseInt(sum,2);
    }

    /**
     *
     * @param bit (int)
     * @param value (int)
     * @brief Setzt den Wert <code>value</code> an Stelle <code>bit</code>
     */
    public void setPortBRegValue(int bit, int value) {

        // save previous value
        setPortBprevRegValue(bit, getPORTBRegValue(bit));

        // save new value
        portB[bit] = value;

    }

    /**
     *
     * @param bit
     * @return bit (int[])
     * @brief Holt den Wert und gibt es als Array zurück
     */
    public int getPORTBRegValue(int bit) {
        return portB[bit];
    }

    /**
     * 
     * @param bit (int)
     * @return bit (int)
     * @brief Gibt den letzten Wert des PortB an Stelle <code>bit</code> zurück
     */
    public int getPORTBprevRegValue(int bit) {
        return portB_prev[bit];
    }

    /**
     *
     * @param bit (int)
     * @param value (int)
     * @brief Speichert den letzten Wert von PortB ab
     */
    public void setPortBprevRegValue(int bit, int value) {
        portB_prev[bit] = value;
    }
    // *********


    // EEDATA
    // 08h EEDATA

    /**
     *
     * @return eedata (int)
     * @brief Holt den Wert aus EEDATA
     */
    public int getEEDATAReg() {
        return eedata;
    }

    /**
     *
     * @param value (int)
     * @brief Schreibt den Parameter <code>value</code> in eedata
     */
    public void setEEDATA(int value) {
        eedata = value;
    }
    // *********

    // EEADR
    // 09h EEADR

    /**
     *
     * @return eeadr (int)
     * @brief Holt den Wert aus EEADR
     */
    public int getEEADRReg() {
        return eeadr;
    }


    /**
     *
     * @param value (int)
     * @brief Schreibt den Parameter <code>value</code> in eeadr
     */
    public void setEEADR(int value) {
        eeadr = value;
    }
    // *********


    // OPTION_REG
    // 81h OPTION_REG RBPU | INTEDG | T0CS | T0SE | PSA | PS2 | PS1 | PS0
    /**
     *
     * @param bit (int)
     * @return value (int)
     * @brief Gibt den Wert des OPTION_REG Registers an Stelle <code>bit</code>
     */
    public int getOptionRegValue(int bit) {        
        
        return optionReg[bit];
        
    }

    /**
     * 
     * @return sum (int)
     * @brief Berechnet den Gesamtwert des OPTION_REG Registers und gibt diesen dann zurück
     */
    public int getOptionRegValueSum() {

        String sum = "";

        for(int i=0; i<optionReg.length; i++) {
            sum = Integer.toString(optionReg[i]) + sum;
        }

        return Integer.parseInt(sum,2);
        
    }

    /**
     * 
     * @param bit (int)
     * @param value (int)
     * @brief Setzt den Wert (<code>value</code>) an Bit (<code>bit</code>) des OPTION_REG Registers
     */
    public void setOptionRegValue(int bit, int value) {        
        
        optionReg[bit] = value;
        
    }
    // *********

    // TRISA
    // 85h TRISA TRISA4 | TRISA3 | TRISA2 | TRISA1 | TRISA0
    /**
     *
     * @param bit (int)
     * @return value (int)
     * @brief Gibt den Wert des TRISA Registers an der Stelle <code>bit</code> zurück
     */
    public int getTrisARegValue(int bit) {

        return trisA[bit];

    }


    /**
     *
     * @return sum (int)
     * @brief Berechnet den Gesamtwert des TRISA Registers und gibt diesen dann zurück
     */
    public int getTrisARegValueSum() {

        String sum = "";

        for(int i=0; i<trisA.length; i++) {
            sum = Integer.toString(trisA[i]) + sum;
        }

        return Integer.parseInt(sum,2);

    }
    


    /**
     *
     * @param bit (int)
     * @param value (int)
     * @brief Setzt den Wert (<code>value</code>) des TRISA Registers an Stelle <code>bit</code>
     */
    public void setTrisARegValue(int bit, int value) {

        trisA[bit] = value;

    }
    // *********

    // TRISB
    // 86h TRISB TRISB7 | TRISB6 | TRISB5 | TRISB4 | TRISB3 | TRISB2 | TRISB1 | TRISB0
    /**
     *
     * @param bit (int)
     * @return value (int)
     * @brief Gibt den Wert des TRISB Registers an der Stelle <code>bit</code> zurück
     */
    public int getTrisBValue(int bit) {

        return trisB[bit];

    }

    /**
     *
     * @return sum (int)
     * @brief Berechnet den Gesamtwert des TRISA Registers und gibt diesen dann zurück
     */
    public int getTrisBRegValueSum() {

        String sum = "";        

        for(int i=0; i<trisB.length; i++) {
            sum = Integer.toString(trisB[i]) + sum;
        }

        return Integer.parseInt(sum,2);

    }

    /**
     *
     * @param bit (int)
     * @param value (int)
     * @brief Setzt den Wert (<code>value</code>) des TRISB Registers an Stelle <code>bit</code>
     */
    public void setTrisBRegValue(int bit, int value) {

        trisB[bit] = value;

    }
    // *********


    // EECON1 Register
    // 88h EECON1 - | - | - | EEIF | WRERR | WREN | WR | RD

    /**
     *
     * @return sum (int)
     * @brief Schreibt den Parameter <code>value</code> in eedata
     */
    public int getEECON1RegValueSum() {

        String sum = "";

        for(int i=0; i<eecon1.length; i++) {
            sum = Integer.toString(eecon1[i]) + sum;
        }

        return Integer.parseInt(sum,2);
        
    }

    /**
     * 
     * @param bit (int)
     * @param value (int)
     * @brief Speichert den Wert aus dem Parameter <code>value</code> in eecon1 an Stelle <code>bit</code>
     */
    public void setEECON1RegValue(int bit, int value) {
        eecon1[bit] = value;
    }

    /**
     *
     * @param bit (int)
     * @return value (int)
     * @brief Holt den Wert von eecon1
     */
    public int getEECON1RegValue(int bit) {
        return eecon1[bit];
    }
    // *********


    // PCLATH Register
    // 0Ah - | - | - | (5 bits)
    /**
     *
     * @return pclathsum (int)
     * @brief Gibt die Summe des PCLATH-Registers zurück
     */
    public int getPCLATHRegValueSum() {

        String sum = "";

        for(int i=0; i<pclath.length; i++) {
            sum = Integer.toString(pclath[i]) + sum;
        }

        return Integer.parseInt(sum,2);

    }

    /**
     * 
     * @param bit (int)
     * @param value (int)
     * @brief Speichert den Wert <code>value</code> an Stelle <code>bit</code>
     */
    public void setPCLATHRegValue(int bit, int value) {
        pclath[bit] = value;
    }

    /**
     * 
     * @param bit (int)
     * @return value (int)
     * @brief Holt den Wert des PCLATH Registers
     */
    public int getPCLATHRegValue(int bit) {
        return pclath[bit];
    }
    // *********

    // INTCON Register
    // 0Bh GIE | EEIE | T0IE | INTE | RBIE | T0IF | INTF | RBIF
    /**
     *
     * @return intconsum (int)
     * @brief Gibt die Summe des INTCON Registers zurück
     */
    public int getINTCONRegValueSum() {

        String sum = "";

        for(int i=0; i<intcon.length; i++) {
            sum = Integer.toString(intcon[i]) + sum;
        }

        return Integer.parseInt(sum,2);

    }

    /**
     * 
     * @param bit (int)
     * @param value (int)
     * @brief Setzt den Wert <code>value</code> an Stelle <code>bit</code>
     */
    public void setINTCONRegValue(int bit, int value) {
        intcon[bit] = value;
    }

    /**
     * 
     * @param bit (int)
     * @return value (int)
     * @brief Holt den Wert des INCTON Registers an Stelle <code>bit</code>
     */
    public int getINTCONRegValue(int bit) {
        return intcon[bit];
    }
    // *********


    /**
     * @brief Zurücksetzen des Speichers auf die entsprechenden Standard-Werte
     */
    public void resetMemory() {

        setPCL(0);
        setW(0);
        wdt = 0;

        setMemoryToValueOnPowerOn();

        stack.clearStack();

    }

    /**
     * @brief Standard-Werte setzen ("Value on Power-on and Reset") Set <code>x</code> = 0
     */
    public void setMemoryToValueOnPowerOn() {

        bank1 = false;

        instCounter = 0;

        realTimeDuration = 0;

        // init SRAM: all to 0
        for(int i=0; i<sram.length; i++) {
            sram[i] = 0;
        }

        
        // Special Function Register
        
        // #####
        // BANK0
        // #####
        
        // 01h TMR0
        tmr0 = 0;

        // 02h PCL
        setPCL(0);

        // 03h STATUS:
        // 0001 1000
        for(int i=0; i<statusReg.length; i++) {
            if(i == 3 || i == 4) statusReg[i] = 1; // After power-up = 1
            else statusReg[i] = 0;
        }

        // 04h FSR
        fsr = 0;

        // 05h PORTA
        for(int i=0; i<portA.length; i++) {
            portA[i] = 0;
        }

        for(int i=0; i<portA_prev.length; i++) {
            portA_prev[i] = -1;
        }

        // 06h PORTB
        for(int i=0; i<portB.length; i++) {
            portB[i] = 0;
        }

        for(int i=0; i<portB_prev.length; i++) {
            portB_prev[i] = -1;
        }

        // 07h --> unimplemented!!

        // 08h EEDATA
        eedata = 0;

        // 09h EEADR
        eeadr = 0;

        // 0Ah PCLATH:
        // ---0 0000
        for(int i=0; i<pclath.length; i++) {
            pclath[i] = 0;
        }

        // 0Bh INTCON:
        // 0000 0000
        for(int i=0; i<intcon.length; i++) {
            intcon[i] = 0;
        }

        // #####
        // BANK1
        // #####

        // 80h INDF -> not a physical register

        // 81h OPTION_REG:
        // 1111 1111
        for(int i=0; i<optionReg.length; i++) {
            optionReg[i] = 1;
        }

        // 82h PCL = 02h
        
        // 83h STATUS = 03h
        
        // 84h FSR = 04h
        
        // 85h TRISA:
        // ---1 1111
        for(int i=0; i<trisA.length; i++) {
            trisA[i] = 1;
        }
        
        // 86h TRISB
        // 1111 1111
        for(int i=0; i<trisB.length; i++) {
            trisB[i] = 1;
        }

        // 87h = 07h --> not implemented

        // 88h EECON1
        // ---0 0000
        for(int i=0; i<eecon1.length; i++) {
            eecon1[i] = 0;
        }

        // 89h EECON2 --> not a physical register

        // 8Ah PCLATH
        // ---0 0000
        for(int i=0; i<pclath.length; i++) {
            pclath[i] = 0;
        }

        // 8Bh INTCON = 08h
        

    }

    
    // PCL
    /**
     * @brief Aktuellen Wert des PCL um eins erhöhen
     */
    public void setPCL() {
        pcl++;
    }

    /**
     *
     * @param value (int)
     * @brief Wert des PCL auf den übergebenen Wert setzen
     */
    public void setPCL(int value) {
        pcl = value;
    }

    /**
     *
     * @return pcl (int)
     * @brief Gibt den aktuellen Wert des PCL zurück
     */
    public int getPCL() {
        return pcl;
    }
    // *********


    // W-Reg
    /**
     *
     * @param value (int)
     * @brief Wert des W-Registers auf den übergebenen Wert setzen
     */
    public void setW(int value) {
        w = value;
    }

    /**
     *
     * @return w (int)
     * @brief Gibt den aktuellen Wert des W-Registers zurück
     */
    public int getW() {
        return w;
    }
    // *********


    /**
     * 
     * @return bank (int)
     * @brief Gibt den Wert true (= 1) für Bank1 und den Wert false (= 0)für Bank 0 zurück
     */
    public boolean getActualBank() {
        if(bank1) return true; // = 1
        else return false; // = 0
    }


    // Schnittstellen zum Stack
    /**
     *
     * @return stack (int[])
     * @brief Liefert den kompletten Stack zurück
     */
    public int[] getStack() {
        return stack.getStack();
    }

     /**
     *
     * @return true|false (boolean)
     * @brief Prüft, ob der Stack voll ist.
     */
    public boolean isStackFull() {
        return stack.isStackFull();
    }

    /**
     *
     * @param stackelement (int)
     * @throws Exception
     * @brief Schiebt ein Element über das aktuellste Element auf dem Stack
     */
    public void push(int stackelement) {
        try {            
            stack.push(stackelement);
        }
        catch(Exception e) {
           gui.showDialog("error", "Stack voll", "Der Stack hat die maximale Kapazität von 8 Elementen erreicht.");
        }
    }

    /**
     *
     * @return result (int)
     * @brief Holt das aktuellste Element vom Stack und liefert es zurück.
     */
    public int pop() {
        return stack.pop();
    }
    
    // *********

    /**
     * 
     * @param opcode (String)
     * @brief Speichert den letzten Opcode zur Weitergabe ab
     */
    public void saveLastOpcode(String opcode) {
        lastOpcode = opcode;
    }

    /**
     * 
     * @return lastOpcode (String)
     * @brief Gibt den letzten Opcode zurück
     */
    public String getLastOpcode() {
        return lastOpcode;
    }
}
